
const { ccclass, property } = cc._decorator;

export enum EPoolType {
    Block,
}

export enum EPrefabType {
    Block = "Item/ItemBlock",
}

/** 节点数据 */
export interface IPoolData {
    prefab: cc.Prefab;
    pool: cc.NodePool;
    node: cc.Node;
}

@ccclass
export default class PoolManager {
    private static _instance: PoolManager = null;

    /**
     * @private
     * @type {Map<cc.NodePool, cc.Prefab>}
     * @memberof PoolManager
     */
    private prefabDatas: Map<cc.NodePool, cc.Prefab> = new Map();

    private _poolBlock: cc.NodePool = new cc.NodePool();
    public get poolBullet() {
        return this._poolBlock;
    }

    public static get instance() {
        if (this._instance === null) {
            this._instance = new this();
        }
        return this._instance;
    }

    /** 初始化对象池 */
    public async setupBefore() {
        const now = Date.now();
        await this.initSinglePool(this._poolBlock, EPrefabType.Block, 100);

        console.log(`PoolManager.initSinglePool()===>对象池加载时长:${Date.now() - now}`);
    }

    /**
     * 设置对象池
     * @param pool 
     * @param type
     * @param value 创建数量
     */
    private async initSinglePool(pool: cc.NodePool, type: EPrefabType, value: number) {
        const self = this;
        const prefabUrl = `prefab/${type}`;
        return new Promise<any>(function (resolve, reject) {
            cc.loader.loadRes(prefabUrl, cc.Prefab, function (err, prefab) {
                if (err) {
                    console.log(err.message || err);
                    return;
                }
    
                for (let i = 0; i < value; ++i) {
                    const node = cc.instantiate(prefab);
                    pool.put(node);
                }
                self.prefabDatas.set(pool, prefab);
                resolve(`init over~`);
            }.bind(this));
        });
    }

    /**
     * 根据对象池类型返回数据
     * @param type 
     * @param parent 
     * @param position
     * @returns 
     */
    public getSingleByType(type: EPoolType, parent: cc.Node, position: cc.Vec2): IPoolData {
        const data: IPoolData = {
            prefab: null,
            pool: null,
            node: null,
        }
        switch (type) {
            case EPoolType.Block:
                data.pool = this._poolBlock;
                data.prefab = this.getPrefab(this._poolBlock);
                break;
        }
        if (data.pool.size() > 0) {
            data.node = data.pool.get();
        } else {
            data.node = cc.instantiate(data.prefab);
        }
        data.node.parent = parent;
        data.node.setPosition(position);
        return data;
    }

    /**
     * 把节点回收到对象池
     * @param node 
     * @param pool 
     */
    public recycleNode(node: cc.Node, pool: cc.NodePool) {
        node.angle = 0;
        node.setPosition(cc.v3(0, 0, 0));
        node.parent = null;
        pool.put(node);
    }

    /**
     * 根据对象池取对应预制体
     * @param pool
     * @returns 
     */
    private getPrefab(pool: cc.NodePool) {
        const prefab = this.prefabDatas.get(pool);
        return prefab;
    }
}